package com.woody.aggregate.application.service.msgsendrule.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woody.aggregate.application.service.msgsendrule.IMsgSendRuleTargetRefService;
import com.woody.aggregate.domain.msgsendrule.MsgSendRuleManager;
import com.woody.aggregate.domain.msgsendrule.MsgSendRuleTargetRefManager;
import com.woody.aggregate.infrastructure.messagebox.dto.MessageboxCountDTO;
import com.woody.aggregate.infrastructure.messagebox.mapper.MessageboxConfigMapper;
import com.woody.aggregate.infrastructure.msgsendrule.entity.MsgSendRule;
import com.woody.aggregate.infrastructure.msgsendrule.entity.MsgSendRuleTargetRef;
import com.woody.aggregate.msgsendrule.enums.MsgSendUserScopeEnum;
import com.woody.aggregate.msgsendrule.enums.MsgSendUserTypeEnum;
import com.woody.aggregate.msgsendrule.vo.RuleTargetInfoVo;
import com.woody.base.exception.BaseException;
import com.woody.base.model.Response;
import com.woody.base.user.api.dto.merchant.BatchQueryShopListDTO;
import com.woody.base.user.api.vo.ShopVO;
import com.woody.base.user.api.vo.merchant.BasicShopV2VO;
import com.woody.base.user.feign.merchant.ShopFeign;
import com.woody.base.util.ResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 弹窗规则关联目标表 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-03-20
 */
@Service
@Slf4j
public class MsgSendRuleTargetRefServiceImpl implements IMsgSendRuleTargetRefService {

    @Autowired
    private MsgSendRuleTargetRefManager ruleTargetRefManager;

    @Autowired
    private MessageboxConfigMapper messageboxConfigMapper;

    @Autowired
    private MsgSendRuleManager msgSendRuleManager;

    @Autowired
    private ShopFeign shopFeign;

    /**
     * 分页查询规则绑定的用户列表
     * <br />
     *
     * @param page
     * @param ruleId
     * @return
     */
    @Override
    public Page<RuleTargetInfoVo> queryTargetsByRuleId(Page page, Integer ruleId) {
        Page<MsgSendRuleTargetRef> sendRuleDtoPage = ruleTargetRefManager.pageQueryTargets(page, ruleId);
        Page<RuleTargetInfoVo> resultPage = new Page<>(sendRuleDtoPage.getCurrent(), sendRuleDtoPage.getSize(), sendRuleDtoPage.getTotal());

        if (CollectionUtils.isEmpty(sendRuleDtoPage.getRecords())) {
            return resultPage;
        }

        List<RuleTargetInfoVo> records = new ArrayList<>();
        resultPage.setRecords(records);

        // 查询推送目标基础信息，如店铺名，并转换vo对象
        List<RuleTargetInfoVo> returnVos = getRuleTargetInfoVos(sendRuleDtoPage);
        records.addAll(returnVos);
        return resultPage;
    }

    /**
     * 过滤并返回规则已绑定的用户列表
     * <br />
     *
     * @param ruleId
     * @param targetType
     * @param bizIds
     * @return 已绑定的用户列表
     */
    @Override
    public List<Long> getBoundTargets(Integer ruleId, Integer targetType, List<Long> bizIds) {
        return ruleTargetRefManager.getBoundTargets(ruleId, targetType, bizIds);
    }

    /**
     * 更新规则精准推送的用户列表
     * <br />
     *
     * @param ruleId 规则ID
     * @param targetType 目标类型
     * @param addUserIds 需要添加的用户ID列表
     * @param removeUserIds 需要移除的用户ID列表
     * @param operatorUserId 操作用户ID
     */
    @Override
    public void updateTargetRef(Integer ruleId, Integer targetType, List<Long> addUserIds, List<Long> removeUserIds, Long operatorUserId) {

        // 校验新增与删除是否存在冲突
        if (addUserIds.stream().anyMatch(removeUserIds::contains)) {
            throw new BaseException("同一个推送用户新增与删除列表中不能同时存在");
        }

        // 校验规则是否存在
        MsgSendRule rule = msgSendRuleManager.getById(ruleId);
        if (rule == null) {
            throw new BaseException("规则不存在或已被删除");
        }

        // 校验弹窗规则推送用户目标范围，如果是全部用户，则不可编辑
        if (MsgSendUserScopeEnum.ALL.getScope().equals(rule.getUserScope())) {
            throw new BaseException("推送范围为全部用户，不能增加或删除目标用户");
        }

        // 校验规则是否被弹窗使用
        List<MessageboxCountDTO> dtos = messageboxConfigMapper.countByRuleIds(Collections.singletonList(ruleId));
        // 弹窗状态：1=启用；0=禁用
        if (dtos.stream().anyMatch(o -> o.getStatus().equals(1) && o.getNum() > 0)) {
            throw new BaseException("该规则存在启用中的弹窗，请禁用后再编辑");
        }


        // 删除需要移除的推送目标
        if (CollectionUtils.isNotEmpty(removeUserIds)) {
            LambdaQueryWrapper<MsgSendRuleTargetRef> wrapper = new LambdaQueryWrapper<MsgSendRuleTargetRef>()
                    .in(MsgSendRuleTargetRef::getBizId, removeUserIds);
            ruleTargetRefManager.getBaseMapper().delete(wrapper);
        }

        // 添加新的推送目标
        if (CollectionUtils.isNotEmpty(addUserIds)) {
            // 过滤掉已存在的
            List<Long> boundTargets = getBoundTargets(ruleId, targetType, addUserIds);
            addUserIds.removeAll(boundTargets);
            // 过滤完为空
            if (addUserIds.isEmpty()) {
                return;
            }
            Date currentTime = new Date();
            // 创建目标引用列表
            List<MsgSendRuleTargetRef> targetInfoList = addUserIds.stream().distinct().map(uid -> {
                return new MsgSendRuleTargetRef() {{
                    setRuleId(ruleId);
                    setTargetType(targetType);
                    setBizId(uid);
                    setCreateUserId(operatorUserId);
                    setCreateTime(currentTime);
                }};
            }).collect(Collectors.toList());
            // 保存目标引用列表
            ruleTargetRefManager.saveBatch(targetInfoList);
        }
    }

    /**
     * 查询推送目标基础信息，如店铺名，并转换vo对象
     * <br />
     * @param sendRuleDtoPage
     * @return
     */
    private List<RuleTargetInfoVo> getRuleTargetInfoVos(Page<MsgSendRuleTargetRef> sendRuleDtoPage) {
        // 门店id => 门店信息
        Map<Long, BasicShopV2VO> shopInfoMap = new HashMap<>();

        // <目标类型，目标业务id列表>
        Map<Integer, List<MsgSendRuleTargetRef>> targetMap = sendRuleDtoPage.getRecords().stream().collect(Collectors.groupingBy(MsgSendRuleTargetRef::getTargetType));
        for (Map.Entry<Integer, List<MsgSendRuleTargetRef>> entry : targetMap.entrySet()) {
            Integer type = entry.getKey();
            List<MsgSendRuleTargetRef> list = entry.getValue();
            if (MsgSendUserTypeEnum.SHOP.getType().equals(type)) {
                List<Long> shopIds = list.stream().map(MsgSendRuleTargetRef::getBizId).collect(Collectors.toList());
                // 查询门店名称
                try {
                    BatchQueryShopListDTO batchQueryShopListDTO = new BatchQueryShopListDTO();
                    batchQueryShopListDTO.setShopIds(shopIds);
                    batchQueryShopListDTO.setNeedShopLogo(false);
                    Response<List<BasicShopV2VO>> shopInfosResp = shopFeign.batchQueryShopList(batchQueryShopListDTO);
                    List<BasicShopV2VO> sucRes = ResponseUtil.getSucRes(shopInfosResp);
                    shopInfoMap = sucRes.stream().collect(Collectors.toMap(BasicShopV2VO::getShopId, Function.identity(), (a, b) -> a));
                } catch (Exception e) {
                    // 门店名查不到不影响业务功能，只记录日志，不抛异常
                    log.error("门店信息查询失败", e);
                }

            } else {
                throw new BaseException("推送目标类型暂不支持");
            }
        }

        Map<Long, BasicShopV2VO> finalShopInfoMap = shopInfoMap;

        // 转换vo
        return sendRuleDtoPage.getRecords().stream().map(ref -> {
            RuleTargetInfoVo ruleTargetInfoVo = new RuleTargetInfoVo();
            ruleTargetInfoVo.setBizId(ref.getBizId());
            ruleTargetInfoVo.setTargetType(ref.getTargetType());

            if (MsgSendUserTypeEnum.SHOP.getType().equals(ref.getTargetType())) {
                BasicShopV2VO shopVO = finalShopInfoMap.get(ref.getBizId());
                ruleTargetInfoVo.setBizName(shopVO != null ? shopVO.getShopName() : "");
            }
            return ruleTargetInfoVo;
        }).collect(Collectors.toList());
    }
}
